package cn.itcast.bos.web.action.user;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.springframework.context.annotation.Scope;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;

import cn.itcast.bos.domain.user.User;
import cn.itcast.bos.web.action.base.BaseAction;

import com.opensymphony.xwork2.interceptor.annotations.InputConfig;

@Controller("userAction")
@Scope("prototype")
@Namespace("/user")
@ParentPackage("bos")
@Result(name = "login_param_error", location = "/login.jsp")
public class UserAction extends BaseAction<User> {

	// 如何接受 checkbox 选中数据?
	private String[] roleIds;

	public void setRoleIds(String[] roleIds) {
		this.roleIds = roleIds;
	}

	@Action(value = "userAction_pageQuery")
	public String pageQuery() {
		Map<String, Object> results = new HashMap<String, Object>();
		// 1: Pageable 接口封装 datagrid 请求 page rows 当前页面和每页记录数
		Pageable pageRequest = new PageRequest(page - 1, rows);
		// 业务将调用spring-data接口实现 完成分页查询 获取分页数据返回值 Page对象
		Page<User> pageData = userService.findAll(pageRequest);
		// Page [{},{},{}] List<T> 实现Itrerable 接口 json 序列化 数组 [{},{}]
		results.put("total", pageData.getTotalElements());// map 封装 easyui datagrid 插件需要数据格式 total 和 rows
		results.put("rows", pageData.getContent());
		getValueStack().push(results);
		return SUCCESS;
	}

	// 为什么不可以使用重定向 服务器 给浏览器 发送头信息 302 第一次请求已经结束了 浏览器会发起新的请求 来自客户端
	@Action(value = "userAction_save", results = { @Result(name = "save", location = "/WEB-INF/pages/admin/userlist.jsp") })
	// @InputConfig(resultName = "login_param_error")
	public String save() {
		userService.save(model, roleIds);
		return "save";
	}

	// 退出系统方法
	@Action(value = "userAction_logout")
	public String logout() {
		Subject subject = SecurityUtils.getSubject();
		subject.logout();
		return "no_login";
	}

	// 修改密码 业务 ajax 请求接收
	@Action(value = "userAction_editPassword")
	public String editPassword() {
		Map<String, Object> results = new HashMap<String, Object>();
		try {
			User existUser = (User) getSessionData("existUser");
			if (existUser != null) {
				userService.updateUserPasswordByUsername(existUser.getUsername(), model.getPassword());// 数据库账号 添加唯一性约束
			}
			results.put("flag", true);
		} catch (Exception e) {
			e.printStackTrace();
			results.put("flag", false);
		}
		// struts2-json-plugin.xml 插件 自动获取值栈的数据 将数据 自动序列化json格式
		// 插件源码中 两种方式获取值栈数据
		getValueStack().push(results);// 压入栈顶 不需要配置root 插件自动将栈顶序列化 json 格式数据
		return SUCCESS;
	}

	@Action(value = "userAction_login", results = { @Result(name = "login_error", location = "/login.jsp"), @Result(name = "login_ok", location = "/index.jsp", type = "redirect") })
	@InputConfig(resultName = "login_param_error")
	public String login() {
		// 表单提交用户名和密码
		// 1: 验证码校验
		String input_code = (String) getParameter("checkcode");
		String session_code = (String) getSessionData("key");
		// 判断用户输入验证码是否为空
		if (StringUtils.isNotBlank(input_code)) {
			// 比较验证码是否匹配
			if (input_code.equalsIgnoreCase(session_code)) {
				// 验证码正确 一次性验证码
				removeSessionData("key");
				// 2: 表单参数校验 // xml 版本 struts2 参数校验器... 参数非法 默认 DefaultWorkFlowIntercepter INPUT结果集跳转
				// 3: 查询数据库 用户名和密码是否匹配
				// User existUser = userService.findUserByUsernameAndPassword(model.getUsername(), model.getPassword());
				// if (existUser == null) {
				// // 数据库查询不到该用户
				// this.addActionError(this.getText("login.code.usernameOrpassword.error"));
				// return "login_error";// login.jsp
				// } else {
				// // 查询用户
				// setSessionData("existUser", existUser);
				// return "login_ok";// 登陆成功
				// }
				// 使用apache shiro Subject 获取subject---> 安全管理器 (客户提交用户名和密码)--->调用realm (自定义realm 调用数据库查询)
				try {
					Subject subject = SecurityUtils.getSubject();
					// 创建令牌 接受 客户端提交用户名和密码
					AuthenticationToken token = new UsernamePasswordToken(model.getUsername(), model.getPassword());
					subject.login(token);// 没有返回值
					// login 设计: 如果代码Ok 认证通过 没有异常抛出的 如果认证失败 没有通过 抛出异常
					// setSessionData("existUser", existUser);
					return "login_ok";
				} catch (UnknownAccountException e) {
					// 验证码错误
					this.addActionError(this.getText("login.unknown.account.exception.error"));
					return "login_error";// login.jsp
				} catch (IncorrectCredentialsException e) {
					// 验证码错误
					this.addActionError(this.getText("login.incorrect.credentials.exception.error"));
					return "login_error";// login.jsp
				}

			} else {
				// 验证码错误
				this.addActionError(this.getText("login.code.input.error"));
				return "login_error";
			}

		} else {
			// 用户没有输入验证码
			this.addActionError(this.getText("login.code.required.error"));
			return "login_error";
		}

	}
}
